package com.xinsoft.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xinsoft.common.exception.BDException;
import com.xinsoft.constant.Const;
import com.xinsoft.entity.dto.InOrOutStock;
import com.xinsoft.entity.dto.ScmSaleReturnDTO;
import com.xinsoft.entity.dto.ScmSaleReturnParam;
import com.xinsoft.entity.po.*;
import com.xinsoft.entity.vo.ScmSaleOutstockListVo;
import com.xinsoft.entity.vo.ScmSaleReturnListVo;
import com.xinsoft.entity.vo.ScmSaleReturnVo;
import com.xinsoft.mapper.ScmSaleReturnItemMapper;
import com.xinsoft.service.*;
import com.xinsoft.mapper.ScmSaleReturnMapper;
import com.xinsoft.utils.TokenUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author ZYM
 * @description 针对表【scm_sale_return(销售退货)】的数据库操作Service实现
 * @createDate 2023-07-21 16:06:17
 */
@Service
public class ScmSaleReturnServiceImpl extends ServiceImpl<ScmSaleReturnMapper, ScmSaleReturn>
        implements ScmSaleReturnService {
    @Resource
    private ScmSaleReturnItemMapper scmSaleReturnItemMapper;

    @Autowired
    private ScmStockService stockService;
    @Autowired
    private SysDocumentNumService sysDocumentNumService;
    @Autowired
    private ScmDocumentService documentService;
    @Autowired
    private SysFileHisService fileHisService;
    @Autowired
    private ScmSaleReturnItemService saleReturnItemService;
    @Autowired
    private ScmSaleOutstockService saleOutstockService;
    @Autowired
    private SysMaterialService materialService;

    @Override
    public IPage<ScmSaleReturnListVo> findPageListByParam(ScmSaleReturnParam param) {
        Page<ScmSaleReturnListVo> page = new Page<>(param.getCurrentPage(), param.getPageSize());
        return baseMapper.findPageListByParam(page, param);
    }

    @Override
    public List<ScmSaleReturnListVo> findListByParam(ScmSaleReturnParam param) {
        // IPage的参数 size<0 ，临时不分页
        Page<ScmSaleReturnListVo> page = new Page<>(param.getCurrentPage(), -1);
        IPage<ScmSaleReturnListVo> pageListByParam = baseMapper.findPageListByParam(page, param);
        return pageListByParam.getRecords();
    }

    @Override
    public Integer tempSave(ScmSaleReturnDTO scmSaleReturnDTO) {
        ScmSaleReturn saleReturn = new ScmSaleReturn();
        BeanUtils.copyProperties(scmSaleReturnDTO, saleReturn);
        saleReturn.setAuditStatus(Const.AUDIT_STATUS_WAIT);
        List<ScmSaleReturnItem> saleReturnItemList = scmSaleReturnDTO.getScmSaleReturnItemList();
        this.checkNum(saleReturnItemList);
        // 保存或新增
        if (Objects.isNull(saleReturn.getId())) {
            // 更新计划单号
            sysDocumentNumService.incrementLastSerialByDocumentId(Const.DOCUMENT_ID.SALE_RETURN_DOCUMENT);
            this.save(saleReturn);
        } else {
            documentService.remove(Wrappers.lambdaQuery(ScmDocument.class).eq(ScmDocument::getScmId, saleReturn.getId()));
            saleReturnItemService.remove(Wrappers.lambdaQuery(ScmSaleReturnItem.class).eq(ScmSaleReturnItem::getSaleReturnId, saleReturn.getId()));
            this.updateById(saleReturn);
        }

        // 保存销售退货明细
        saleReturnItemList.forEach(item -> {
            item.setSaleReturnId(saleReturn.getId());
            item.setSourceType(Const.ApproveType.XSCK);
        });
        saleReturnItemService.saveBatch(saleReturnItemList);
        // 保存附件
        List<SysFileHis> fileHisList = scmSaleReturnDTO.getSysFileHisList();
        documentService.saveDocument(fileHisList, saleReturn.getId(), Const.ApproveType.XSTH);
        return saleReturn.getId();
    }

    /**
     * 校验数量
     *
     * @param itemList    生产领用明细
     */
    public void checkNum(List<ScmSaleReturnItem> itemList) {
        List<String> failMsgList = new ArrayList<>();
        List<Integer> sourceIds = itemList.stream().map(ScmSaleReturnItem::getSourceId).distinct().collect(Collectors.toList());
        List<Integer> materialIds = itemList.stream().map(ScmSaleReturnItem::getMaterialId).distinct().collect(Collectors.toList());
        List<SysMaterial> sysMaterials = materialService.listByIds(materialIds);
        Map<Integer, String> materialMap = sysMaterials.stream().collect(Collectors.toMap(SysMaterial::getId, SysMaterial::getMaterialName));
        // 校验可执行数量
        //关联销售出库
        List<ScmSaleOutstockListVo> list = saleOutstockService.findList(sourceIds, materialIds);
        Map<String, ScmSaleOutstockListVo> voMap = list.stream().collect(Collectors.toMap(vo -> String.join("_", vo.getId().toString(), vo.getMaterialId().toString()), vo -> vo));
        itemList.forEach(item -> {
            String key = String.join("_", item.getSourceId().toString(), item.getMaterialId().toString());
            if (voMap.containsKey(key) && item.getReturnNum().compareTo(voMap.get(key).getPrimaryUnitCount()) > 0) {
                failMsgList.add(String.format("物料[%s]批次为[%s]的源单可用数量[%s]", materialMap.get(item.getMaterialId()), item.getBatch(), voMap.get(key).getPrimaryUnitCount()));
            }
        });
        if (CollectionUtil.isNotEmpty(failMsgList)) {
            failMsgList.add("退货数量不能大于源单可用数量");
            throw new BDException(String.join(",\n", failMsgList));
        }
    }


    @Override
    public ScmSaleReturnVo detail(Integer id) {
        ScmSaleReturnVo saleReturnVo = baseMapper.getSaleReturnById(id);
        // 销售退货明细
        saleReturnVo.setScmSaleReturnItemList(scmSaleReturnItemMapper.listBySaleReturnId(id));
        // 附件列表
        saleReturnVo.setSysFileHisList(documentService.getFileHisListByScmId(id, Const.ApproveType.XSTH));
        return saleReturnVo;
    }

    @Override
    public void del(List<Integer> ids) {
        List<ScmSaleReturn> list = this.list(Wrappers.lambdaQuery(ScmSaleReturn.class)
                .eq(ScmSaleReturn::getAuditStatus, Const.AUDIT_STATUS_NORMAL)
                .in(ScmSaleReturn::getId, ids));
        if (list.size() > 0) {
            throw new BDException("操作失败，只能删除暂存的销售出库单");
        }
        saleReturnItemService.remove(Wrappers.lambdaQuery(ScmSaleReturnItem.class).in(ScmSaleReturnItem::getSaleReturnId, ids));
        documentService.remove(Wrappers.lambdaQuery(ScmDocument.class).in(ScmDocument::getScmId, ids));
        this.removeByIds(ids);
    }

    @Override
    public void audit(Integer id) {
        ScmSaleReturn saleReturn = this.getById(id);
        if (Const.AUDIT_STATUS_NORMAL.equals(saleReturn.getAuditStatus())) {
            throw new BDException("该单据已审核，无需重复审核");
        }
        List<ScmSaleReturnItem> itemList = saleReturnItemService.list(Wrappers.lambdaQuery(ScmSaleReturnItem.class)
                .eq(ScmSaleReturnItem::getSaleReturnId, id));
        this.checkNum(itemList);
        this.update(Wrappers.lambdaUpdate(ScmSaleReturn.class)
                .eq(ScmSaleReturn::getId, id)
                .set(ScmSaleReturn::getAuditStatus, Const.AUDIT_STATUS_NORMAL)
                .set(ScmSaleReturn::getAuditId, TokenUtil.getUserId())
                .set(ScmSaleReturn::getAuditTime, new Date()));
        // 更新库存
        List<InOrOutStock> inOrOutStockList = this.getInOrOutStockList(id);
        stockService.updateInventory(Const.SourceBillType.XSTH, saleReturn.getSaleOutstockNo(), inOrOutStockList, Const.ChangeType.ADD);
    }

    @Override
    public void reverseAudit(Integer id) {
        ScmSaleReturn saleReturn = this.getById(id);
        if (Const.AUDIT_STATUS_WAIT.equals(saleReturn.getAuditStatus())) {
            throw new BDException("该单据未审核，无需反审核");
        }
        saleReturn.setAuditId(null);
        saleReturn.setAuditTime(null);
        saleReturn.setAuditStatus(Const.AUDIT_STATUS_WAIT);
        this.updateById(saleReturn);
        // 更新库存
        List<InOrOutStock> inOrOutStockList = this.getInOrOutStockList(id);
        stockService.updateInventory(Const.SourceBillType.XSTH, saleReturn.getSaleOutstockNo(), inOrOutStockList, Const.ChangeType.SUBTRACT);
    }

    /**
     * 获取出入库明细列表
     * @param id
     * @return {@link List}<{@link InOrOutStock}>
     */
    public List<InOrOutStock> getInOrOutStockList(Integer id) {
        List<InOrOutStock> list = new ArrayList<>();
        List<ScmSaleReturnItem> items = saleReturnItemService.list(Wrappers.lambdaQuery(ScmSaleReturnItem.class).eq(ScmSaleReturnItem::getSaleReturnId, id));
        items.forEach(item -> {
            InOrOutStock inOrOutStock = new InOrOutStock();
            BeanUtils.copyProperties(item,inOrOutStock);
            inOrOutStock.setQty(item.getReturnNum());
            list.add(inOrOutStock);
        });
        return list;
    }

    @Override
    public void addOrUpdateAudit(ScmSaleReturnDTO scmSaleReturnDTO) {
        Integer id = this.tempSave(scmSaleReturnDTO);
        this.audit(id);
    }
}




